#pragma once

#include <iostream>
#include <queue>

#include <pthread.h>

#include "Task.hpp"
#include "Log.hpp"

#define NUM 6

class ThreadPool
{
private:
    int num;    // 多少个线程
    bool stop;  
    std::queue<Task> task_queue;    // 任务队列
    pthread_mutex_t lock;     // 锁
    pthread_cond_t cond;    // 锁的条件变量

    // 设置成为单例模式
    static ThreadPool* _sInst;
private:
    ThreadPool(int _num = NUM)
        :num(_num),stop(false)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
    }

    ThreadPool(const ThreadPool&){}

    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
public:
    // 设置一个类调用接口，设置线程池为单例模式
    static ThreadPool* GetInstance()
    {
        static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
        if(_sInst == nullptr){
            pthread_mutex_lock(&_mutex);
            if(_sInst == nullptr){
                _sInst = new ThreadPool();
                _sInst->InitThreadPool();
            }
        }
        return _sInst;
    }
    // 将要执行的任务放入任务队列
    void PushTask(const Task &task)
    {
        Lock();
        task_queue.push(task);
        Unlock();
        ThreadWackUp();     // 任务队列中有了任务，要唤醒线程
    }
    // 要做任务了，将任务从任务队列中放出
    void PopTask(Task &task)
    {
        task = task_queue.front();
        task_queue.pop();
    }
private:
    // 判断任务队列是否为空（是否有任务存在）
    bool TaskQueueIsEmpty()
    {
        return task_queue.empty();
    }

    // 加锁
    void Lock()
    {
        pthread_mutex_lock(&lock);
    }

    // 解锁
    void Unlock()
    {
        pthread_mutex_unlock(&lock);
    }

    // 线程等待
    void ThreadWait()
    {
        pthread_cond_wait(&cond, &lock);
    }

    // 唤醒线程
    void ThreadWackUp()
    {
        pthread_cond_signal(&cond);
    }

    // 线程要执行的代码内容
    static void *ThreadRoutinue(void *args)
    {
        ThreadPool *tp = (ThreadPool*)(args);
        while(true)
        {
            Task t;
            tp->Lock();
            while (tp->TaskQueueIsEmpty()){
                // 没有任务存在，让线程等待
                tp->ThreadWait();
            }
            // 此时一定是有任务的
            tp->PopTask(t);     // 将任务从任务队列中移走（“执行任务”）
            tp->Unlock();
            t.ProcessOn();
        }
    }

    // 初始化线程池
    bool InitThreadPool()
    {
        for(int i = 0; i < num; i++)
        {
            pthread_t tid;
            if(pthread_create(&tid, nullptr, ThreadRoutinue, this) != 0){
                LOG(Fatal, "create thread pool error");
                return false;
            }
        }
        LOG(Info, "create thread pool success");
        return true;
    }
};

ThreadPool* ThreadPool::_sInst = nullptr;